/*
 * Copyright 2007-2009 Perttu "celeron55" Ahola <celeron55@gmail.com>
 *
 * This file is part of jukumagic.
 *
 * jukumagic is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jukumagic is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jukumagic.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "footprintlibrary.h"
#include "tinyxml/tinyxml.h"
#include <iostream>
#include <wx/wx.h>
#include <wx/dir.h>
#include <algorithm>
#include <vector>

FootprintLibrary::FootprintLibrary(wxString dirpath)
{
	AddDir(dirpath);
}

FootprintLibrary::FootprintLibrary()
{
}

FootprintLibrary::~FootprintLibrary()
{
	for(std::list<FootprintLibraryNode*>::iterator i = m_nodes.begin(); i != m_nodes.end(); i++){
		delete (*i);
	}
}

bool FootprintLibrary::AddFile(const wxString &filepath)
{
	//std::cout<<"FootprintLibrary::AddFile(\""<<filepath.mb_str(wxConvUTF8)<<"\")"<<std::endl;
	TiXmlDocument doc(filepath.mb_str(wxConvUTF8));
	if(!doc.LoadFile()){
		std::cout<<"FootprintLibrary::AddFile(\""<<filepath.mb_str(wxConvUTF8)
				<<"\"): doc.LoadFile() failed"<<std::endl;
		return false;
	}
	if(doc.Error()){
		std::cout<<"FootprintLibrary::AddFile(\""<<filepath.mb_str(wxConvUTF8)
				<<"\"): doc.Error()"<<std::endl;
		return false;
	}

	TiXmlElement *root = doc.FirstChildElement("Jukumagic");
	if(root){
		int version;
		root->Attribute("version", &version);
		//std::cout<<"root found, version="<<version<<std::endl;
		TiXmlElement *e1 = root->FirstChildElement("FootprintLibraryNode");
		FootprintLibraryNode *node = (FootprintLibraryNode*)FootprintLibraryNode::ReadFromXMLElement(e1);
		if(node){
			m_nodes.push_back(node);
			//TODO: maybe a bit slow here
			ReportChange(OBJECT_CHANGE_CONTENTS);
			//std::cout<<"node successfully added"<<std::endl;
			return true;
		}
	}
	return false;
}

/*bool FootprintLibrary::AddPCBFile(const wxString &filepath)
{
	std::cout<<"FootprintLibrary::AddPCBFile(\""<<filepath.mb_str(wxConvUTF8)<<"\")"<<std::endl;
	return false;
}*/

bool FootprintLibrary::AddDir(const wxString &dirpath)
{
	//std::cout<<"FootprintLibrary::AddDirectory("<<dirpath.mb_str(wxConvUTF8)<<")"<<std::endl;
	if(!wxDir::Exists(dirpath)) return false;
	wxDir dir(dirpath);
	if(!dir.IsOpened()){
		std::cout<<"FootprintLibrary::AddDir(\""<<dirpath.mb_str(wxConvUTF8)
				<<"\"):failed to open dir"<<std::endl;
		return false;
	}
	wxString filename;
	bool c;
	c = dir.GetFirst(&filename, wxT("*.jfln"), wxDIR_FILES);
	while(c){
		//std::cout<<"FootprintLibrary::AddDir(): adding "<<filename.mb_str(wxConvUTF8)<<std::endl;
		AddFile(dirpath + wxT("/") + filename);
		c = dir.GetNext(&filename);
	}

	// PCB Footprints
	/*c = dir.GetFirst(&filename, wxT("*.fp"), wxDIR_FILES);
	while(c){
		//std::cout<<"FootprintLibrary::AddDir(): fp "<<filename.mb_str(wxConvUTF8)<<std::endl;
		AddPCBFile(dirpath + wxT("/") + filename);
		c = dir.GetNext(&filename);
	}*/
	
	// Add subdirs also
	c = dir.GetFirst(&filename, wxT("*"), wxDIR_DIRS /*| wxDIR_HIDDEN*/);
	while(c){
		//std::cout<<"FootprintLibrary::AddDir(): adding "<<filename.mb_str(wxConvUTF8)<<std::endl;
		AddDir(dirpath + wxT("/") + filename);
		c = dir.GetNext(&filename);
	}
	return true;
}

void FootprintLibrary::AddNode(FootprintLibraryNode* node)
{
	m_nodes.push_back(node);
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

void FootprintLibrary::AddFootprint(Footprint* footprint, wxString name)
{
	FootprintLibraryNode *node = new FootprintLibraryNode();
	if(node == NULL) return;
	node->m_name = name;
	node->Add(footprint, NULL);
	AddNode(node);
}

bool Comp(FootprintLibraryNode *n1, FootprintLibraryNode *n2)
{
	return n1->m_name < n2->m_name;
}

void FootprintLibrary::Sort()
{
	std::vector<FootprintLibraryNode*> nodesv;
	nodesv.insert(nodesv.begin(), m_nodes.begin(), m_nodes.end());
	sort(nodesv.begin(), nodesv.end(), Comp);
	m_nodes.clear();
	m_nodes.insert(m_nodes.begin(), nodesv.begin(), nodesv.end());
}

std::list<FootprintLibraryNode*> FootprintLibrary::GetMatchingNodes(const wxString &s)
{
	std::list<FootprintLibraryNode*> matching;
	for(std::list<FootprintLibraryNode*>::iterator i = m_nodes.begin(); i != m_nodes.end(); i++){
		if(((*i)->m_name).Lower().Contains(s.Lower())){
			matching.push_back((*i));
		}
	}
	return matching;
}

std::list<Footprint*> FootprintLibrary::GetMatchingFootprints(const wxString &s)
{
	std::list<FootprintLibraryNode*> matching_nodes = GetMatchingNodes(s);
	std::list<Footprint*> footprints;
	for(std::list<FootprintLibraryNode*>::iterator i = matching_nodes.begin();
			i != matching_nodes.end(); i++){
		FootprintLibraryNode *node = (*i);
		for(std::list<JukuObject*>::const_iterator i = node->GetObjects().begin();
				i != node->GetObjects().end(); i++){
			if((*i)->GetType() == TYPE_FOOTPRINT){
				Footprint *f = (Footprint*)(*i);
				footprints.push_back(f);
			}
		}
	}
	return footprints;
}

Footprint* FootprintLibrary::GetFootprint(const wxString &s)
{
	for(std::list<FootprintLibraryNode*>::iterator i = m_nodes.begin(); i != m_nodes.end(); i++){
		if(((*i)->m_name).Lower() == s.Lower()){
			if((*i)->GetObjects().empty()) continue;
			if((*(*i)->GetObjects().begin())->GetType() != TYPE_FOOTPRINT) continue;
			return (Footprint*)(*(*i)->GetObjects().begin());
		}
	}
	return NULL;
}


